/* 
 * StikiWeb Wiki - a Wiki for Hierarchical Organizations
 * $Id: Base62.java,v 1.2 2006/07/20 21:07:53 biglee Exp $
 * 
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the StikiWeb Wiki 
 *
 * The Initial Developer of the Original Code is Lee Haslup (biglee@haslups.com).
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** 
 */
package org.stikiweb.contentMagnager;

import java.io.IOException;
import java.io.StringReader;

/**
 * @author Allen L (BigLee) Haslup
 *
 * This class is a utility class that encodes and decodes
 * strings so that strings containing arbitrary characters
 * are encoded using only mixed case letters and digits.
 */
public class Base62 {
	
	// static utility class -- do not instantiate
	private Base62 () {}
	
	public static final int BASE = 62;
	public static final int BSQUARED = BASE * BASE;
	public static final int ZEROVAL = 0;
	public static final int LILAVAL = 10;
	public static final int BIGAVAL = 36;
	public static final char[] CHARFORVAL = {
		'0','1','2','3','4','5','6','7','8','9',
		'a','b','c','d','e','f','g','h','i','j',
		'k','l','m','n','o','p','q','r','s','t',
		'u','v','w','x','y','z','A','B','C','D',
		'E','F','G','H','I','J','K','L','M','N',
		'O','P','Q','R','S','T','U','V','W','X',
		'Y','Z'
	};
	
	// Encode the string so that each 16 bit character in the
	// input string is represented by three mixed-case alpha-
	// numeric characters in the encoded string.
	public static String encode(String in) {
		StringReader sr = new StringReader(in);
		StringBuffer sb = new StringBuffer();
		try {
			int c = sr.read();
			while(c>=0) {
				sb.append(CHARFORVAL[(c / BSQUARED) % BASE]);
				sb.append(CHARFORVAL[(c / BASE) % BASE]);
				sb.append(CHARFORVAL[c % BASE]);
				c = sr.read();
			}
		} catch (IOException e) {
			// Log problem but go with what we've got.
			e.printStackTrace();
		}
		return sb.toString();
	}
	
	// Decode a string encoded as described above.
	public static String decode(String in) {
		StringReader sr = new StringReader(in);
		StringBuffer sb = new StringBuffer();
		try {
			int c = sr.read();		// start w/ first character
			int counter = 0;		// basis for three-state "step"
			int accumulator = 0;	// used to accumulate each decoded character
			while(c>=0) {
				int step = counter % 3;
				switch (step) {
				case 0:
					accumulator = valForChar(c);
					break;
				case 1:
					accumulator = accumulator*BASE + valForChar(c);
					break;
				case 2:
					accumulator = accumulator*BASE + valForChar(c);
					sb.append((char)accumulator);
				}
				c = sr.read();
				counter++;
			}
		} catch (IOException e) {
			// Log problem but go with what we've got.
			e.printStackTrace();
		}
		return sb.toString();
	}
	
	// helper function used to map a character to its numerical
	// value.  (Reverse of map stored in CHARFORVAL array)
	private static int valForChar(int c) {
		if(c>='0'&&c<='9') {
			return c-'0'+ZEROVAL;
		}
		else if(c>='a'&&c<='z') {
			return c-'a'+LILAVAL;
		}
		else {
			return c-'A'+BIGAVAL;
		}
	}
}
